package logic;

import java.util.List;
import java.util.Iterator;
import java.util.Random;

/**
 * A simple model of a fox.
 * Foxes age, move, eat rabbits, and die.
 * 
 * @author David J. Barnes and Michael Kolling
 * @version 2008.03.30
 */
public class Fox extends Animal
{
    // Characteristics shared by all foxes (static fields).
    
    // The age at which a fox can start to breed.
    private static int BREEDING_AGE = 10;
    // The age to which a fox can live.
    private static int MAX_AGE = 150;
    // The likelihood of a fox breeding.
    private static double BREEDING_PROBABILITY = 0.35;
    // The maximum number of births.
    private static int MAX_LITTER_SIZE = 5;
    // The food value of a single rabbit. In effect, this is the
    // number of steps a fox can go before it has to eat again.
    private static int RABBIT_FOOD_VALUE = 7;
    // The food value of a single duck. In effect, this is the
    // number of steps a fox can go before it has to eat again.
    private static int DUCK_FOOD_VALUE = 3;
    // A shared random number generator to control breeding.
    private static final Random rand = Randomizer.getRandom();
    
    // Individual characteristics (instance fields).
    // The fox's food level, which is increased by eating rabbits.
    private int foodLevel;

    /**
     * Create a fox. A fox can be created as a new born (age zero
     * and not hungry) or with a random age and food level.
     * 
     * @param randomAge If true, the fox will have random age and hunger level.
     * @param field The field currently occupied.
     * @param location The location within the field.
     */
    public Fox(boolean randomAge, Field field, Location location)
    {
        super(field, location);
        if(randomAge) {
            setAge();
            age = getAge();
            foodLevel = rand.nextInt(RABBIT_FOOD_VALUE);
        }
        else {
            age = 0;
            foodLevel = RABBIT_FOOD_VALUE;
        }
    }
    
    /**
     * This is what the fox does most of the time: it hunts for
     * rabbits. In the process, it might breed, die of hunger,
     * or die of old age.
     * @param field The field currently occupied.
     * @param newFoxes A list to add newly born foxes to.
     */
    public void act(List<Actor> newFoxes)
    {
    	incrementAge();
        incrementHunger();
        if(isAlive()) {
            giveBirth(newFoxes, getClass().getName());            
            // Move towards a source of food if found.
            Location location = getLocation();
            Location newLocation = findFood(location);
            if(isAlive()){
	            if(newLocation == null) { 
	                // No food found - try to move to a free location.
	                newLocation = getField().freeAdjacentLocation(location);
	            }
	            // See if it was possible to move.
	            if(newLocation != null) {
	                setLocation(newLocation);
	            }
	            else {
	                // Overcrowding.
	                setDead();
	            }
            }
        }
    }

    
    
    /**
     * Make this fox more hungry. This could result in the fox's death.
     */
    private void incrementHunger()
    {
        foodLevel--;
        if(foodLevel <= 0) {
            setDead();
        }
    }
    
    /**
     * Tell the fox to look for rabbits adjacent to its current location.
     * Only the first live rabbit is eaten.
     * @param location Where in the field it is located.
     * @return Where food was found, or null if it wasn't.
     */
    private Location findFood(Location location)
    {
        Field field = getField();
        List<Location> adjacent = field.adjacentLocations(getLocation());
        Iterator<Location> it = adjacent.iterator();
        while(it.hasNext()) {
            Location where = it.next();
            Object actor = field.getObjectAt(where);
            if(actor instanceof Rabbit) {
                Rabbit rabbit = (Rabbit) actor;
                if(rabbit.isAlive()) { 
                    rabbit.setDead();
                    foodLevel = RABBIT_FOOD_VALUE;
                    // Remove the dead rabbit from the field.
                    return where;
                }
            }
            else if(actor instanceof Duck){
            	Duck duck = (Duck) actor;
            	if(duck.isAlive()) {
            	duck.setDead();
            	foodLevel = DUCK_FOOD_VALUE;
                // Remove the dead rabbit from the field.
                return where;
            	}
            }
            
            else if(actor instanceof Grass)
            {
            	Grass grass = (Grass) actor;
            	if(grass.isAlive())
            	{
            		return where;
            	}
            }  
            
            else if(actor instanceof Landmine)
            {
            	Landmine trap = (Landmine) actor;
            	if(trap.isActive())
            	{
            		trap.setInactive();
            		setDead();
            		return where;
            	}
            }
            
        }
        return null;
    }
        
    
    /**
     * Returns the breeding age of this fox
     * @return BREEDING_AGE of this fox
     */
    public int getBreedingAge()
    {
    	return BREEDING_AGE;
    }
    
    /**
     * Returns the maximum age of this fox
     * @return MAX_AGE of this fox
     */
    public int getMaxAge()
    {
    	return MAX_AGE;
    }
    
    /**
     * Returns the likelihood of this fox to breed
     * @return BREEDING_PROBABILITY of this fox
     */
    public double getBreedingProbability()
    {	
    	return BREEDING_PROBABILITY;
    }
    
    /**
     * Returns the maximum number of births of this fox
     * @return MAX_LITTER_SIZE of this fox
     */
    public int getMaxLitterSize()
    {
    	return MAX_LITTER_SIZE;
    }


	@Override
	protected Animal newAnimal(Field field, Location location) 
	{
		Animal fox = new Fox(false, field, location);
		return fox;
	}
	
	/**
	 * Sum's up the characteristics of a fox.
	 * @return String
	 */
	public static String getStatic()
	{
		return 
		"Breeding age: "+ BREEDING_AGE + 
		", Max age: " + MAX_AGE + 
		", Breeding probability: " + BREEDING_PROBABILITY +
		", Max amount of new Foxes: " + MAX_LITTER_SIZE +
		", Rabbit food value: " + RABBIT_FOOD_VALUE +
		", Duck food value: " + DUCK_FOOD_VALUE;
	}
	
	/**
	 * sets the characteristics of the fox.
	 * @param BAge
	 * @param MAge
	 * @param BProbability
	 * @param LitterSize
	 * @param RFood
	 * @param DFood
	 */
	public static void setStatic(int BAge, int MAge, double BProbability, int LitterSize, int RFood, int DFood)
	{
		BREEDING_AGE = BAge;
		MAX_AGE = MAge;
		BREEDING_PROBABILITY = BProbability;  
		MAX_LITTER_SIZE = LitterSize;
		RABBIT_FOOD_VALUE = RFood;
		DUCK_FOOD_VALUE = DFood;
	}
}


